import datetime
import hashlib

from BlockChain.分模块实现简单区块链.Message import DaDaMessage, InvalidMessage
from BlockChain.分模块实现简单区块链.Transaction import Transaction


class Block:
    def __init__(self, *args):  # 初始化
        self.messageList = []  # 存储多个交易记录，存放区块
        self.timestamp = None  # 存储多个记录最终锁定的时间
        self.hash = None  # 当前的哈希散列
        self.prev_hash = None  # 上一块的哈希散列
        if args:
            for arg in args:
                self.add_message(arg)
                # self.messagelist.append(arg)

    def add_message(self, message):  # 增加交易信息
        # 区分第一条与后面多条，是否需要链接
        if len(self.messageList) > 0:
            message.link(self.messageList[-1])  # 链接
        message.seal()  # 密封
        message.validate()  # 校验
        self.messageList.append(message)  # 追加记录

    def link(self, block):  # 区块链链接
        self.prev_hash = block.hash

    def seal(self):  # 密封
        self.timestamp = datetime.datetime.now()  # 密封确定当前时间
        self.hash = self._hash_block()  # 密封当前的哈希值

    def _hash_block(self):  # 密封 上一块哈希，时间线，交易记录的最后一个
        if len(self.messageList) > 0:
            return hashlib.md5((str(self.prev_hash) +
                                str(self.timestamp) +
                                str(self.messageList[-1].hash)).encode("utf-8")).hexdigest()
        # else:
        #     return hashlib.sha256((str(self.prev_hash) +
        #                            str(self.timestamp) +
        #                            str(0)).encode("utf-8")).hexdigest()

    def validate(self):  # 校验
        for i, message in enumerate(self.messageList):  # 校验每一个交易记录
            message.validate()  # 校验每一条
            if i > 0 and message.prev_hash != self.messageList[i - 1].hash:
                raise InvalidBlock("无效block，交易记录被修改为在第{}条记录".format(i) + str(self))
        #         print("无效block，交易记录被修改为在第{}条记录".format(i))
        #         return str(self) + "数据NO"
        return "   " + str(self) + "  数据OK"

    def __repr__(self):  # 类的对象描述
        # return "money block = hash : {}, pre_hash : {}, len : {}, time : {}".\
        #     format(self.hash, self.prev_hash, len(self.messageList), self.timestamp)
        return "money block \n hash : {} \n pre_hash : {} \n len : {} \n time : {}". \
            format(self.hash, self.prev_hash, len(self.messageList), self.timestamp)


class InvalidBlock(Exception):  # block异常
    def __init__(self, *arg, **kargs):
        Exception.__init__(self, *arg, **kargs)


if __name__ == '__main__':
    try:
        t1 = Transaction("x", "y1", 1)
        t2 = Transaction("x", "y2", 2)
        t3 = Transaction("x", "y3", 3)
        t4 = Transaction("x", "y4", 4)

        m1 = DaDaMessage(t1)  # 交易记录
        m2 = DaDaMessage(t2)
        m3 = DaDaMessage(t3)
        m4 = DaDaMessage(t4)

        # yin = Block(m1, m2, m3, m4)
        yin = Block(m1)
        yin.seal()
        # m4.hash = "nisxx"
        # yin.messageList[2] = m2
        print(yin.validate())
    except InvalidBlock as e:  # 区块被修改
        print(e)
    except InvalidMessage as e:  # 消息被修改
        print(e)
